package com.th.coupon.service.impl;

import com.google.common.base.Stopwatch;
import com.th.coupon.common.constant.Constant;
import com.th.coupon.dao.CouponTemplateDao;
import com.th.coupon.entity.CouponTemplate;
import com.th.coupon.service.IAsyncService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;


import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 异步服务实现
 * @author 涂航
 */
@Slf4j
@Service
public class IAsyncServiceImpl implements IAsyncService {

    /**
     * {@link CouponTemplateDao}优惠卷模板持久层
     */
    private final CouponTemplateDao couponTemplateDao;
    /**
     * {@link StringRedisTemplate} redis操作
     */
    private final StringRedisTemplate stringRedisTemplate;
    @Autowired
    public IAsyncServiceImpl(CouponTemplateDao couponTemplateDao, StringRedisTemplate stringRedisTemplate) {
        this.couponTemplateDao = couponTemplateDao;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * 根据模板异步的创建优惠卷码
     * @param template {@link CouponTemplate} 优惠卷模板实体
     */
    @Override
    @Async("getAsyncExecutor")
    public void asyncConstructCouponByTemplate(CouponTemplate template) {
        Stopwatch watch = Stopwatch.createStarted();
        //生成优惠卷码
        Set<String> couponCodes = buildCouponCode(template);
        //优惠卷key
        String redisKey = String.format("%s%s", Constant.RedisPrefix.COUPON_TEMPLATE,template.getId().toString());

        log.info("Push CouponCode To Reids: {}",stringRedisTemplate.opsForList().rightPushAll(redisKey,couponCodes));

        //设置是否可用
        template.setAvailable(true);

        couponTemplateDao.save(template);

        watch.stop();

        log.info("Construct CouponCode By Template Cost: {}ms",watch.elapsed(TimeUnit.MILLISECONDS));

        //TODO 发送短信或者邮件通知优惠卷模板已经可用
        log.info("CouponTemplate({}) Is Available!",template.getId());
    }

    /**
     * 构造优惠卷码
     * 优惠卷码 （对应于每一张优惠卷 18位）
     * 前4位 ：产品线+类型
     * 中间6位 ： 日期随机（200306）
     *  后8位 ： 0 - 9 随机数构成
     * @param couponTemplate {@link CouponTemplate} 实体类
     * @return {@link Set} 与CouponTemplate.count相同个数的集合
     */
    private Set<String> buildCouponCode(CouponTemplate couponTemplate){
        Stopwatch watch = Stopwatch.createStarted();
        Set<String> result = new HashSet<String>();

        //前四位
        String prefix4 = couponTemplate.getProductLine().getCode() + couponTemplate.getCategory().getCode();
        //中间6位
        String date = new SimpleDateFormat("yyMMdd").format(couponTemplate.getCreateTime());

        for (int i = 0; i < result.size(); i++) {
            result.add(prefix4+buildCouponCodeSuffix14(date));
        }
        while (result.size() < couponTemplate.getCount()){
            result.add(prefix4+buildCouponCodeSuffix14(date));
        }

        assert  result.size() == couponTemplate.getCount();

        watch.stop();

        log.info("build Coupon Code Cost:{}ms",watch.elapsed(TimeUnit.MILLISECONDS));

        return result;
    }

    /**
     * 构造位符卷码后 14位
     * @param date 创建优惠卷的日期
     * @return {@link String} 14位优惠卷码
     */
    private String buildCouponCodeSuffix14(String date){
        char[] bases = new char[]{'1','2','3','4','5','6','7','8','9'};

        //中间6位
        List<Character> collect = date.chars().mapToObj(e -> (char) e).collect(Collectors.toList());
        //洗牌重排算法
        Collections.shuffle(collect);
        //前62位
        String mid6 = collect.stream().map(Objects::toString).collect(Collectors.joining());
        //后8位
        String suffix8 = RandomStringUtils.random(1,bases) +  RandomStringUtils.randomNumeric(7);
        return mid6+suffix8;
    }
}
